package com.cenntro.oss.service.impl;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Resource;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.cenntro.common.base.BaseServiceImpl;
import com.cenntro.common.mapper.SysconfMapper;
import com.cenntro.common.model.dbo.SysconfDO;
import com.cenntro.common.redis.IRedisService;
import com.cenntro.common.util.NumUtil;
import com.cenntro.oss.common.VehicleConstant;
import com.cenntro.oss.mapper.DevPartitionExtMapper;
import com.cenntro.oss.model.dbo.DevPartitionExtDO;
import com.cenntro.oss.service.DevPartitionExtService;
import com.google.common.collect.ImmutableMap;

@Service
public class DevPartitionExtServiceImpl extends BaseServiceImpl<DevPartitionExtMapper> implements DevPartitionExtService {
	@Resource
	private DevPartitionExtMapper devPartitionExtMapper;
	@Resource
	private IRedisService redisService;
	@Resource
	private SysconfMapper sysconfMapper;


	/**
	 * 根据devId 查询 或者生成的分片序号
	 * 
	 * @param vincode
	 * @return
	 */
	public String getGeneratePartitionNum(Integer devId) {
		if(devId == null){
			return "000";
		}
		String key  = VehicleConstant.DEV_PARTITION + devId;
		String v = redisService.get(key, String.class);
		try {
			if (StringUtils.isNotBlank(v)) {
				return v;
			} else {
				return "000";
			}
		} finally {
			//log.info("getGeneratePartitionNum cost : {}", System.currentTimeMillis() - st);
		}
	}

	/**
	 * partition 数字转成字符串，前面补零
	 * @param partition
	 * @return
	 */
	public String getPartition(int partition) {
		StringBuilder sb = new StringBuilder(partition + "");
		while (sb.length() < 3) {
			sb.insert(0, 0);
		}
		return sb.toString();
	}

//	/**
//	 * 查询未分配PartitionNum 的devid
//	 */
//	@Override
//	public List<Integer> select4UnAlloction() {
//		return devPartitionExtMapper.select4UnAlloction();
//	}
	
	/**
	 * 对devId 分配 PartitionNum
	 * 对新的dev做分配，存入 redis(key,field,value)->("partition_num", 分区序号，分配dev个数)。
	 * 如果dev个不能超过sysconf.getValue 配置，超过以后创建下一个partition
	 * @param devid 车辆id
	 */
	public void selectPartitionNum(Integer devId){
		if (devId == null || redisService.get(VehicleConstant.DEV_PARTITION + devId, String.class) != null){
			return;
		}
		
		String key  = VehicleConstant.PARTITION_NUM;
		String str = null;
		SysconfDO sysconf = new SysconfDO();
		sysconf.setCode(VehicleConstant.DEV_PARTITION_NUM);
		sysconf.setStatus(1);
		sysconf = sysconfMapper.selectSysconf(sysconf);
		int partNum = 0;
		try{
			if (redisService.tryLock(VehicleConstant.LOCK_DEV_PARTITION)) {
				Map<String, Integer> partition_numMap = redisService.hmget(VehicleConstant.PARTITION_NUM);  //取出当前分区信息（key，）
				int maxPartitionNum = 0;  //最大分区表50
				int newCount = 0;  //分配dev个数
				if(MapUtils.isNotEmpty(partition_numMap)){
					for(Entry<String, Integer> en : partition_numMap.entrySet()){
						if(en.getValue() < NumUtil.toInt(sysconf.getValue())){  //dev个数不满，就加入该表
							newCount = en.getValue() + 1;
							maxPartitionNum = NumUtil.toInt(en.getKey());
							break;
						}
						//找出最大partition_num 然后+1
						int num = NumUtil.toInt(en.getKey());
						maxPartitionNum = num >= maxPartitionNum ? num +1 : maxPartitionNum;
						newCount = 1;
					}
				}else{
					maxPartitionNum = 1; 
					newCount = 1;
				}
				str = getPartition(maxPartitionNum);
				redisService.hset(key, str, newCount);
				redisService.set(VehicleConstant.DEV_PARTITION + devId, str + "");  //设置devId所在的partitionNum
				devPartitionExtMapper.createTable("vehicle_upload_track" + maxPartitionNum); //不存在就创建新表
				DevPartitionExtDO ext = new DevPartitionExtDO();
		        ext.setDevId(devId);
		        ext.setPartitionNum(str);
		        devPartitionExtMapper.insert(ext);
			}else {
//				partNum = 0;
//				str = getPartition(partNum);
//				redisService.set(key, str);
			}
		}finally{
			redisService.remove(VehicleConstant.LOCK_DEV_PARTITION);
		}
		
	}
	
	/**
	 * 根据devid 删除 devPartitionExtMapper，并删除redis
	 */
	@Override
	public void deleteByDevId(Integer devId) {
		if(devId != null){
			DevPartitionExtDO devPartitionExt =	devPartitionExtMapper.selectOne(ImmutableMap.of("devId", devId));
			if (devPartitionExt != null){
				try{
					if (redisService.tryLock(VehicleConstant.LOCK_DEV_PARTITION)) {
						Integer count = redisService.hget(VehicleConstant.PARTITION_NUM, devPartitionExt.getPartitionNum());
						count = count > 1 ? count -1: 0;
						redisService.hset(VehicleConstant.PARTITION_NUM, devPartitionExt.getPartitionNum(), count);
						redisService.remove(VehicleConstant.DEV_PARTITION + devId);
					}
					devPartitionExtMapper.deleteByDevId(devId);
				}finally{
					redisService.remove(VehicleConstant.LOCK_DEV_PARTITION);
				}
			}
		}
	}
	
}
